home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / GAMES / C014.ZIP / LARN_SRC.ZIP / IO.C < prev    next >
C/C++ Source or Header  |  1993-11-17  |  32KB  |  1,137 lines

  1. /* io.c
  2.  *
  3.  *  setupvt100()    Subroutine to set up terminal in correct mode for game
  4.  *  clearvt100()    Subroutine to clean up terminal when the game is over
  5.  *  ttgetch()       Routine to read in one character from the terminal
  6.  *  scbr()          Function to set cbreak -echo for the terminal
  7.  *  sncbr()         Function to set -cbreak echo for the terminal
  8.  *  newgame()       Subroutine to save the initial time and seed rnd()
  9.  *
  10.  *  FILE OUTPUT ROUTINES
  11.  *
  12.  *  lprintf(format,args . . .)  printf to the output buffer
  13.  *  lprint(integer)         send binary integer to output buffer
  14.  *  lwrite(buf,len)         write a buffer to the output buffer
  15.  *  lprcat(str)         sent string to output buffer
  16.  *
  17.  *  FILE OUTPUT MACROS (in header.h)
  18.  *
  19.  *  lprc(character)         put the character into the output buffer
  20.  *
  21.  *  FILE INPUT ROUTINES
  22.  *
  23.  *  long lgetc()            read one character from input buffer
  24.  *  long lrint()            read one integer from input buffer
  25.  *  lrfill(address,number)      put input bytes into a buffer
  26.  *  char *lgetw()           get a whitespace ended word from input
  27.  *  char *lgetl()           get a \n or EOF ended line from input
  28.  *
  29.  *  FILE OPEN / CLOSE ROUTINES
  30.  *
  31.  *  lcreat(filename)        create a new file for write
  32.  *  lopen(filename)         open a file for read
  33.  *  lappend(filename)       open for append to an existing file
  34.  *  lrclose()           close the input file
  35.  *  lwclose()           close output file
  36.  *  lflush()            flush the output buffer
  37.  *
  38.  *  Other Routines
  39.  *
  40.  *  cursor(x,y)     position cursor at [x,y]
  41.  *  cursors()       position cursor at [1,24] (saves memory)
  42.  *  cl_line(x,y)            Clear line at [1,y] and leave cursor at [x,y]
  43.  *  cl_up(x,y)          Clear screen from [x,1] to current line.
  44.  *  cl_dn(x,y)      Clear screen from [1,y] to end of display. 
  45.  *  standout(str)       Print the string in standout mode.
  46.  *  set_score_output()  Called when output should be literally printed.
  47.  ** ttputch(ch)     Print one character in decoded output buffer.
  48.  ** flush_buf()     Flush buffer with decoded output.
  49.  ** init_term()     Terminal initialization -- setup termcap info
  50.  ** char *tmcapcnv(sd,ss)   Routine to convert VT100 \33's to termcap format
  51.  *  beep()          Routine to emit a beep if enabled (see no-beep in .larnopts)
  52.  *
  53.  * Note: ** entries are available only in termcap mode.
  54.  */
  55.  
  56. #include "header.h"
  57. #include "larndefs.h"
  58. #include <ctype.h>
  59.  
  60. #ifdef SYSV /* system III or system V */
  61. # ifndef MSDOS
  62. #   include <termio.h>
  63. # endif
  64. #define sgttyb termio
  65. #define stty(_a,_b) ioctl(_a,TCSETA,_b)
  66. #define gtty(_a,_b) ioctl(_a,TCGETA,_b)
  67. #ifndef MSDOS
  68. static int rawflg = 0;
  69. static char saveeof,saveeol;
  70. #define doraw(_a) if(!rawflg){++rawflg;saveeof=_a.c_cc[VMIN];saveeol=_a.c_cc[VTIME];}\
  71.     _a.c_cc[VMIN]=1;_a.c_cc[VTIME]=1;_a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL)
  72. #define unraw(_a) _a.c_cc[VMIN]=saveeof;_a.c_cc[VTIME]=saveeol;_a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL
  73. #endif
  74. #else not SYSV
  75. #ifdef VMS
  76. #include    <descrip.h>
  77. #include    <ssdef.h>
  78. #include    <stsdef.h>
  79. #include    <iodef.h>
  80. #include    <ttdef.h>
  81. #include    <tt2def.h>
  82. #else VMS
  83. #ifndef BSD
  84. #define CBREAK RAW      /* V7 has no CBREAK */
  85. #endif
  86. #define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO)
  87. #define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO)
  88. #include <sgtty.h>
  89. #endif not SYSV
  90. #endif VMS
  91.  
  92. #ifndef NOVARARGS   /* if we have varargs */
  93. #include <varargs.h>
  94. #else NOVARARGS /* if we don't have varargs */
  95. typedef char *va_list;
  96. #define va_dcl int va_alist;
  97. #define va_start(plist) plist = (char *) &va_alist
  98. #define va_end(plist)
  99. #define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1]
  100. #endif NOVARARGS
  101.  
  102. #define LINBUFSIZE 128      /* size of the lgetw() and lgetl() buffer       */
  103. int lfd;            /*  output file numbers     */
  104. int fd;             /*  input file numbers      */
  105. # ifndef MSDOS
  106. # ifndef VMS
  107. static struct sgttyb ttx;   /* storage for the tty modes                    */
  108. # else
  109. int iochan;         /* storage for the tty channel  */
  110. int ttx[3];         /* storage for the tty modes    */
  111. int cbflag;         /* cbreak flag.  Set when SCBRd */
  112. # endif
  113. # endif
  114. static int ipoint=MAXIBUF,iepoint=MAXIBUF;  /*  input buffering pointers    */
  115. static char lgetwbuf[LINBUFSIZE];   /* get line (word) buffer               */
  116.  
  117. #ifdef MSDOS
  118. # include <setjmp.h>
  119.  extern jmp_buf save_jbuf;
  120.  extern int save_mode;
  121. #endif
  122.  
  123. # ifdef MSDOS
  124. # include <fcntl.h>     /* For O_BINARY */
  125. static int (*getchfn)();
  126. int getche(), kgetch();
  127. # endif
  128.  
  129. /*
  130.  *  setupvt100()        Subroutine to set up terminal in correct mode for game
  131.  *
  132.  *  Attributes off, clear screen, set scrolling region, set tty mode 
  133.  */
  134. setupvt100()
  135.     {
  136. #ifdef VMS
  137.     struct  dsc$descriptor  idsc;
  138.     register int        status;
  139.  
  140.     idsc.dsc$a_pointer = "SYS$COMMAND";
  141.     idsc.dsc$w_length  = strlen(idsc.dsc$a_pointer);
  142.     idsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  143.     idsc.dsc$b_class   = DSC$K_CLASS_S;
  144.     status = SYS$ASSIGN(&idsc, &iochan, 0, 0);
  145.     if (status&STS$M_SUCCESS == 0)
  146.         exit(status);
  147. #endif
  148.     lprc(T_INIT);
  149.     clear();  setscroll();  scbr(); /* system("stty cbreak -echo"); */
  150. # ifdef MSDOS
  151.     setraw();
  152.     setcursor();
  153.  
  154.     /* Select normal ASCII and line drawing character sets.
  155.      */
  156.     if (DECRainbow)
  157.         lprcat("\033(B\033)0");
  158. # endif
  159.     }
  160.  
  161. /*
  162.  *  clearvt100()        Subroutine to clean up terminal when the game is over
  163.  *
  164.  *  Attributes off, clear screen, unset scrolling region, restore tty mode 
  165.  */
  166. clearvt100()
  167.     {
  168.     lprc(T_END);
  169.     resetscroll();  clear();  sncbr(); /* system("stty -cbreak echo"); */
  170. # ifdef MSDOS
  171.     unsetraw();
  172.     resetcursor();
  173. # endif
  174. #ifdef VMS
  175.     SYS$DASSGN(iochan);
  176. #endif
  177.     }
  178.  
  179. /*
  180.  *  ttgetch()       Routine to read in one character from the terminal
  181.  */
  182.  
  183. #ifdef VMS
  184.  
  185. ttgetch()
  186. {
  187. #define NIBUF   80      /* characters in the buffer.    */
  188.     static char ibuf[NIBUF];
  189.     static int  ibufi = 0;
  190.     static int  nibuf = 0;
  191.     int status;
  192.     int iosb[2];
  193.     int term[2];
  194.  
  195.     lflush();       /* be sure output buffer is flushed */
  196.     term[0] = 0;
  197.     term[1] = 0;
  198.     while (ibufi >= nibuf) {
  199.         if (cbflag) {
  200.         /* cbroken */
  201.             ibufi   = 0;
  202. /*
  203.             status = SYS$QIOW(0, iochan, IO$_READLBLK|IO$M_TIMED,
  204.                  iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
  205. */
  206.             status = SYS$QIOW(0, iochan, IO$_READLBLK,
  207.                  iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
  208.         if (status != SS$_NORMAL)
  209.             continue;
  210.         status = iosb[0] & 0xFFFF;
  211.         if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
  212.             continue;
  213.         nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  214.         if (nibuf == 0) 
  215.         {
  216.         status = SYS$QIOW(0, iochan, IO$_READLBLK,
  217.             iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
  218.         if (status != SS$_NORMAL)
  219.             continue;
  220.         if ((iosb[0]&0xFFFF) != SS$_NORMAL)
  221.             continue;
  222.         nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  223.         }
  224.         } else {
  225.         /* not cbroken */
  226.         try_again:
  227.             ibufi    = 0;
  228.             status   = SYS$QIOW(0, iochan, IO$_READLBLK, iosb,
  229.                     0, 0, ibuf, NIBUF, 0, 0, 0, 0);
  230.             if (status != SS$_NORMAL)
  231.                 goto try_again;
  232.             if ((iosb[0]&0xFFFF) != SS$_NORMAL)
  233.                 goto try_again;
  234.             nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  235.         }
  236.     }
  237.     if ((ibuf[ibufi]&0xFF) == '\r')     /* carriage return */
  238.         ibuf[ibufi] = '\n';     /* turns to newline */
  239.     return (ibuf[ibufi++]&0xFF);
  240. }
  241. #else VMS
  242.  
  243. ttgetch()
  244.     {
  245.     char byt;
  246. #ifdef EXTRA
  247.     c[BYTESIN]++;
  248. #endif EXTRA
  249.     lflush();       /* be sure output buffer is flushed */
  250. # ifdef MSDOS
  251.     if ((byt = (*getchfn)()) == '\r')
  252.         byt = '\n';
  253.     return byt;
  254. # else MSDOS
  255.     read(0,&byt,1);     /* get byte from terminal */
  256.     return(byt);
  257. # endif MSDOS
  258.     }
  259. # endif VMS
  260.  
  261. /*
  262.  *  scbr()      Function to set cbreak -echo for the terminal
  263.  *
  264.  *  like: system("stty cbreak -echo")
  265.  */
  266. scbr()
  267.     {
  268. # ifdef MSDOS
  269.     /* Set up to use the direct console input call which may
  270.      * read from the keypad;
  271.      */
  272.     getchfn = kgetch;
  273. # else
  274. # ifdef VMS
  275.     int status;
  276.     int iosb[2];
  277.  
  278.     cbflag = 1;
  279.     status = SYS$QIOW(0, iochan, IO$_SENSEMODE, iosb, 0, 0,
  280.               ttx, sizeof(ttx), 0, 0, 0, 0);
  281.     if (status&STS$M_SUCCESS == 0)
  282.         exit(status);
  283.     ttx[1] |= TT$M_NOECHO;
  284.     ttx[2] |= TT2$M_PASTHRU;
  285.     status = SYS$QIOW(0, iochan, IO$_SETMODE, iosb, 0, 0,
  286.               ttx, sizeof(ttx), 0, 0, 0, 0);
  287.     if (status&STS$M_SUCCESS == 0)
  288.         exit(status);
  289. # else
  290.     gtty(0,&ttx);       doraw(ttx);     stty(0,&ttx);
  291. # endif
  292. # endif
  293.     }
  294.  
  295. /*
  296.  *  sncbr()     Function to set -cbreak echo for the terminal
  297.  *
  298.  *  like: system("stty -cbreak echo")
  299.  */
  300. sncbr()
  301.     {
  302. # ifdef MSDOS
  303.     /* Set up to use the direct console input call with echo, getche()
  304.      */
  305.     getchfn = getche;
  306. # else
  307. # ifdef VMS
  308.     int status;
  309.     int iosb[2];
  310.     cbflag = 0;
  311.     status = SYS$QIOW(0, iochan, IO$_SENSEMODE, iosb, 0, 0,
  312.               ttx, sizeof(ttx), 0, 0, 0, 0);
  313.     if (status&STS$M_SUCCESS == 0)
  314.         exit(status);
  315.     ttx[1] &= ~TT$M_NOECHO;
  316.     ttx[2] &= ~TT2$M_PASTHRU;
  317.     status = SYS$QIOW(0, iochan, IO$_SETMODE, iosb, 0, 0,
  318.               ttx, sizeof(ttx), 0, 0, 0, 0);
  319.     if (status&STS$M_SUCCESS == 0)
  320.         exit(status);
  321. # else
  322.     gtty(0,&ttx);       unraw(ttx);     stty(0,&ttx);
  323. # endif
  324. # endif
  325.     }
  326.  
  327. /*
  328.  *  newgame()       Subroutine to save the initial time and seed rnd()
  329.  */
  330. newgame()
  331. {
  332.     register long *p,*pe;
  333.     for (p=c,pe=c+100; p<pe; *p++ =0);
  334.     time(&initialtime);
  335.     srand(initialtime);
  336.     lcreat((char*)0);   /* open buffering for output to terminal */
  337. }
  338.  
  339. /*
  340.  *  lprintf(format,args . . .)      printf to the output buffer
  341.  *      char *format;
  342.  *      ??? args . . .
  343.  *
  344.  *  Enter with the format string in "format", as per printf() usage
  345.  *      and any needed arguments following it
  346.  *  Note: lprintf() only supports %s, %c and %d, with width modifier and left
  347.  *      or right justification.
  348.  *  No correct checking for output buffer overflow is done, but flushes 
  349.  *      are done beforehand if needed.
  350.  *  Returns nothing of value.
  351.  */
  352. #ifdef lint
  353. /*VARARGS*/
  354. lprintf(str)
  355.     char *str;
  356.     {
  357.     char *str2;
  358.     str2 = str;
  359.     str = str2; /* to make lint happy */
  360.     }
  361. /*VARARGS*/
  362. sprintf(str)
  363.     char *str;
  364.     {
  365.     char *str2;
  366.     str2 = str;
  367.     str = str2; /* to make lint happy */
  368.     }
  369. #else lint
  370. /*VARARGS*/
  371. lprintf(va_alist)
  372. va_dcl
  373.     {
  374.     va_list ap; /* pointer for variable argument list */
  375.     register char *fmt;
  376.     register char *outb,*tmpb;
  377.     register long wide,left,cont,n;     /* data for lprintf */
  378.     char db[12];            /* %d buffer in lprintf */
  379.  
  380.     va_start(ap);   /* initialize the var args pointer */
  381.     fmt = va_arg(ap, char *);   /* pointer to format string */
  382.     if (lpnt >= lpend) lflush(); 
  383.     outb = lpnt;
  384.     for ( ; ; )
  385.         {
  386.         while (*fmt != '%')
  387.             if (*fmt) *outb++ = *fmt++;  else { lpnt=outb;  return; }
  388.         wide = 0;   left = 1;   cont=1;
  389.         while (cont)
  390.           switch(*(++fmt))
  391.             {
  392.             case 'd':   n = va_arg(ap, long);
  393.                         if (n<0) { n = -n;  *outb++ = '-';  if (wide) --wide; }
  394.                         tmpb = db+11;   *tmpb = (char)(n % 10 + '0');
  395.                         while (n>9)  *(--tmpb) = (char)((n /= 10) % 10 + '0');
  396.                         if (wide==0)  while (tmpb < db+12) *outb++ = *tmpb++;
  397.                         else
  398.                             {
  399.                             wide -= db-tmpb+12;
  400.                             if (left)  while (wide-- > 0) *outb++ = ' ';
  401.                             while (tmpb < db+12) *outb++ = *tmpb++;
  402.                             if (left==0)  while (wide-- > 0) *outb++ = ' ';
  403.                             }
  404.                         cont=0; break;
  405.  
  406.             case 's':   tmpb = va_arg(ap, char *);
  407.                         if (wide==0)  { while (*outb++ = *tmpb++);  --outb; } 
  408.                         else
  409.                             {
  410.                             n = wide - strlen(tmpb);
  411.                             if (left)  while (n-- > 0) *outb++ = ' ';
  412.                             while (*outb++ = *tmpb++);  --outb;
  413.                             if (left==0)  while (n-- > 0) *outb++ = ' ';
  414.                             }
  415.                         cont=0; break;
  416.  
  417.             case 'c':   *outb++ = va_arg(ap, int);  cont=0;  break;
  418.  
  419.             case '0':
  420.             case '1':
  421.             case '2':
  422.             case '3':
  423.             case '4':
  424.             case '5':
  425.             case '6':
  426.             case '7':
  427.             case '8':
  428.             case '9':   wide = 10*wide + *fmt - '0';    break;
  429.  
  430.             case '-':   left = 0;   break;
  431.  
  432.             default:    *outb++ = *fmt;  cont=0;    break;
  433.             };
  434.         fmt++;
  435.         }
  436.     va_end(ap);
  437.     }
  438. #endif lint
  439.  
  440. /*
  441.  *  lprint(long-integer)                send binary integer to output buffer
  442.  *      long integer;
  443.  *
  444.  *      +---------+---------+---------+---------+
  445.  *      |   high  |         |         |   low   |
  446.  *      |  order  |         |         |  order  |
  447.  *      |   byte  |         |         |   byte  |
  448.  *      +---------+---------+---------+---------+
  449.  *     31  ---  24 23 --- 16 15 ---  8 7  ---   0
  450.  *
  451.  *  The save order is low order first, to high order (4 bytes total)
  452.  *      and is written to be system independent.
  453.  *  No checking for output buffer overflow is done, but flushes if needed!
  454.  *  Returns nothing of value.
  455.  */
  456. lprint(x)
  457.     register long x;
  458.     {
  459.     if (lpnt >= lpend) lflush();
  460.     *lpnt++ =  255 & x;         *lpnt++ =  255 & (x>>8);
  461.     *lpnt++ =  255 & (x>>16);   *lpnt++ =  255 & (x>>24);
  462.     }
  463.  
  464. /*
  465.  *  lwrite(buf,len)         write a buffer to the output buffer
  466.  *      char *buf;
  467.  *      int len;
  468.  *  
  469.  *  Enter with the address and number of bytes to write out
  470.  *  Returns nothing of value
  471.  */
  472. lwrite(buf,len)
  473.     register char *buf;
  474.     int len;
  475.     {
  476.     register char *str;
  477.     register int num2;
  478.     if (len > 399)  /* don't copy data if can just write it */
  479.         {
  480. #ifdef EXTRA
  481.         c[BYTESOUT] += len;
  482. #endif
  483.  
  484. #ifndef VT100
  485.         for (str=buf;  len>0; --len)
  486.             lprc(*str++);
  487. #else VT100
  488.         lflush();
  489.         write(lfd,buf,len);
  490. #endif VT100
  491.         } 
  492.     else while (len)
  493.         {
  494.         if (lpnt >= lpend) lflush();    /* if buffer is full flush it   */
  495.         num2 = lpbuf+BUFBIG-lpnt;   /*  # bytes left in output buffer   */
  496.         if (num2 > len) num2=len;
  497.         str = lpnt;  len -= num2;
  498.         while (num2--)  *str++ = *buf++;    /* copy in the bytes */
  499.         lpnt = str;
  500.         }
  501.     }
  502.  
  503. /*
  504.  *  long lgetc()        Read one character from input buffer
  505.  *
  506.  *  Returns 0 if EOF, otherwise the character
  507.  */
  508. long lgetc()
  509.     {
  510.     register int i;
  511.  
  512.     if (ipoint != iepoint)  return(inbuffer[ipoint++]);
  513.     if (iepoint!=MAXIBUF)   return(0);
  514.     if ((i=vread(fd,inbuffer,MAXIBUF))<=0) {
  515.         if (i!=0)
  516.             write(1,"error reading from input file\n",30);
  517.     iepoint = ipoint = 0;
  518.     return(0);
  519.     }
  520.     ipoint=1;  iepoint=i;  return(*inbuffer);
  521. }
  522.  
  523. /*
  524.  *  long lrint()            Read one integer from input buffer
  525.  *
  526.  *      +---------+---------+---------+---------+
  527.  *      |   high  |         |         |   low   |
  528.  *      |  order  |         |         |  order  |
  529.  *      |   byte  |         |         |   byte  |
  530.  *      +---------+---------+---------+---------+
  531.  *     31  ---  24 23 --- 16 15 ---  8 7  ---   0
  532.  *
  533.  *  The save order is low order first, to high order (4 bytes total)
  534.  *  Returns the int read
  535.  */
  536. long lrint()
  537.     {
  538.     register unsigned long i;
  539.     i  = 255 & lgetc();             i |= (255 & lgetc()) << 8;
  540.     i |= (255 & lgetc()) << 16;     i |= (255 & lgetc()) << 24;
  541.     return(i);
  542.     }
  543.  
  544. /*
  545.  *  lrfill(address,number)          put input bytes into a buffer
  546.  *      char *address;
  547.  *      int number;
  548.  *
  549.  *  Reads "number" bytes into the buffer pointed to by "address".
  550.  *  Returns nothing of value
  551.  */
  552. lrfill(adr,num)
  553.     register char *adr;
  554.     int num;
  555.     {
  556.     register char *pnt;
  557.     register int num2;
  558.     while (num)
  559.         {
  560.         if (iepoint == ipoint)
  561.             {
  562.             if (num>5) /* fast way */
  563.                 {
  564.                 if (vread(fd,adr,num) != num)
  565.                     write(2,"error reading from input file\n",30);
  566.                 num=0;
  567.                 }
  568.             else { *adr++ = lgetc();  --num; }
  569.             }
  570.         else
  571.             {
  572.             num2 = iepoint-ipoint;  /*  # of bytes left in the buffer   */
  573.             if (num2 > num) num2=num;
  574.             pnt = inbuffer+ipoint;  num -= num2;  ipoint += num2;
  575.             while (num2--)  *adr++ = *pnt++;
  576.             }
  577.         }
  578.     }
  579.  
  580. /*
  581.  *  char *lgetw()           Get a whitespace ended word from input
  582.  *
  583.  *  Returns pointer to a buffer that contains word.  If EOF, returns a NULL
  584.  */
  585. char *lgetw()
  586.     {
  587.     register char *lgp,cc;
  588.     register int n=LINBUFSIZE,quote=0;
  589.     lgp = lgetwbuf;
  590.     do cc=lgetc();  while ((cc <= 32) && (cc > NULL));  /* eat whitespace */
  591.     for ( ; ; --n,cc=lgetc())
  592.         {
  593.         if ((cc==NULL) && (lgp==lgetwbuf))  return(NULL);   /* EOF */
  594.         if ((n<=1) || ((cc<=32) && (quote==0))) { *lgp=NULL; return(lgetwbuf); }
  595.         if (cc != '"') *lgp++ = cc;   else quote ^= 1;
  596.         }
  597.     }
  598.  
  599. /*
  600.  *  char *lgetl()       Function to read in a line ended by newline or EOF
  601.  *
  602.  *  Returns pointer to a buffer that contains the line.  If EOF, returns NULL
  603.  */
  604. char *lgetl()
  605. {
  606.     register int i=LINBUFSIZE,ch;
  607.     register char *str=lgetwbuf;
  608.     for ( ; ; --i) {
  609.         *str++ = ch = lgetc();
  610.         if (ch == 0) {
  611.             if (str == lgetwbuf+1)
  612.                 return(NULL);   /* EOF */
  613.         ot: *str = 0;
  614.             return(lgetwbuf);   /* line ended by EOF */
  615.         }
  616.         if ((ch=='\n') || (i<=1))
  617.             goto ot;        /* line ended by \n */
  618.     }
  619. }
  620.  
  621. /*
  622.  *  lcreat(filename)            Create a new file for write
  623.  *      char *filename;
  624.  *
  625.  *  lcreat((char*)0); means to the terminal
  626.  *  Returns -1 if error, otherwise the file descriptor opened.
  627.  */
  628. lcreat(str)
  629.     char *str;
  630.     {
  631.     lpnt = lpbuf;   lpend = lpbuf+BUFBIG;
  632.     if (str==NULL) return(lfd=1);
  633.     if ((lfd=creat(str,0644)) < 0) 
  634.         {
  635.         lfd=1; lprintf("error creating file <%s>\n",str); lflush(); return(-1);
  636.         }
  637. # ifdef MSDOS
  638.     setmode(lfd, O_BINARY);
  639. # endif
  640.     return(lfd);
  641.     }
  642.  
  643. /*
  644.  *  lopen(filename)         Open a file for read
  645.  *      char *filename;
  646.  *
  647.  *  lopen(0) means from the terminal
  648.  *  Returns -1 if error, otherwise the file descriptor opened.
  649.  */
  650. lopen(str)
  651.     char *str;
  652.     {
  653.     ipoint = iepoint = MAXIBUF;
  654.     if (str==NULL) return(fd=0);
  655.     if ((fd=open(str,0)) < 0)
  656.         {
  657.         lwclose(); lfd=1; lpnt=lpbuf; return(-1);
  658.         }
  659. # ifdef MSDOS
  660.     setmode(fd, O_BINARY);
  661. # endif
  662.     return(fd);
  663.     }
  664.  
  665. /*
  666.  *  lappend(filename)       Open for append to an existing file
  667.  *      char *filename;
  668.  *
  669.  *  lappend(0) means to the terminal
  670.  *  Returns -1 if error, otherwise the file descriptor opened.
  671.  */
  672. lappend(str)
  673.     char *str;
  674.     {
  675.     lpnt = lpbuf;   lpend = lpbuf+BUFBIG;
  676.     if (str==NULL) return(lfd=1);
  677.     if ((lfd=open(str,2)) < 0)
  678.         {
  679.         lfd=1; return(-1);
  680.         }
  681. # ifdef MSDOS
  682.     setmode(lfd, O_BINARY);
  683. # endif
  684.     lseek(lfd,0L,2);    /* seek to end of file */
  685.     return(lfd);
  686.     }
  687.  
  688. /*
  689.  *  lrclose()                       close the input file
  690.  *
  691.  *  Returns nothing of value.
  692.  */
  693. lrclose()
  694.     {
  695.     if (fd > 0) close(fd);
  696.     }
  697.  
  698. /*
  699.  *  lwclose()                       close output file flushing if needed
  700.  *
  701.  *  Returns nothing of value.
  702.  */
  703. lwclose()
  704.     {
  705.     lflush();   if (lfd > 2) close(lfd);
  706.     }
  707.  
  708. /*
  709.  *  lprcat(string)                  append a string to the output buffer
  710.  *                                  avoids calls to lprintf (time consuming)
  711.  */
  712. lprcat(str)
  713.     register char *str;
  714.     {
  715.     register char *str2;
  716.     if (lpnt >= lpend) lflush(); 
  717.     str2 = lpnt;
  718.     while (*str2++ = *str++);
  719.     lpnt = str2 - 1;
  720.     }
  721.  
  722. #ifdef VT100
  723. /*
  724.  *  cursor(x,y)         Subroutine to set the cursor position
  725.  *
  726.  *  x and y are the cursor coordinates, and lpbuff is the output buffer where
  727.  *  escape sequence will be placed. 
  728.  */
  729. static char *y_num[]= { "\33[","\33[","\33[2","\33[3","\33[4","\33[5","\33[6",
  730.     "\33[7","\33[8","\33[9","\33[10","\33[11","\33[12","\33[13","\33[14",
  731.     "\33[15","\33[16","\33[17","\33[18","\33[19","\33[20","\33[21","\33[22",
  732.     "\33[23","\33[24" };
  733.  
  734. static char *x_num[]= { "H","H",";2H",";3H",";4H",";5H",";6H",";7H",";8H",";9H",
  735.     ";10H",";11H",";12H",";13H",";14H",";15H",";16H",";17H",";18H",";19H",
  736.     ";20H",";21H",";22H",";23H",";24H",";25H",";26H",";27H",";28H",";29H",
  737.     ";30H",";31H",";32H",";33H",";34H",";35H",";36H",";37H",";38H",";39H",
  738.     ";40H",";41H",";42H",";43H",";44H",";45H",";46H",";47H",";48H",";49H",
  739.     ";50H",";51H",";52H",";53H",";54H",";55H",";56H",";57H",";58H",";59H",
  740.     ";60H",";61H",";62H",";63H",";64H",";65H",";66H",";67H",";68H",";69H",
  741.     ";70H",";71H",";72H",";73H",";74H",";75H",";76H",";77H",";78H",";79H",
  742.     ";80H" };
  743.  
  744. cursor(x,y)
  745.     int x,y;
  746.     {
  747.     register char *p;
  748.     if (lpnt >= lpend) lflush();
  749.  
  750.     p = y_num[y];   /* get the string to print */
  751.     while (*p) *lpnt++ = *p++;  /* print the string */
  752.  
  753.     p = x_num[x];   /* get the string to print */
  754.     while (*p) *lpnt++ = *p++;  /* print the string */
  755.     }
  756. #else VT100
  757. /*
  758.  * cursor(x,y)    Put cursor at specified coordinates staring at [1,1] (termcap)
  759.  */
  760. cursor (x,y)
  761.     int x,y;
  762.     {
  763.     if (lpnt >= lpend) lflush ();
  764.  
  765.     *lpnt++ = CURSOR;       *lpnt++ = x;        *lpnt++ = y;
  766.     }
  767. #endif VT100
  768.  
  769. /*
  770.  *  Routine to position cursor at beginning of 24th line
  771.  */
  772. cursors()
  773.     {
  774.     cursor(1,24);
  775.     }
  776.  
  777. #ifndef VT100
  778. /*
  779.  * Warning: ringing the bell is control code 7. Don't use in defines.
  780.  * Don't change the order of these defines.
  781.  * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
  782.  * obvious meanings.
  783.  */
  784.  
  785. static char cap[256];
  786. static char *CM, *CE, *CD, *CL, *SO, *SE, *AL, *DL, *TI, *TE;/* Termcap capabilities */
  787. static char *outbuf=0;  /* translated output buffer */
  788.  
  789. static int ttputch ();
  790.  
  791. /*
  792.  * init_term()      Terminal initialization -- setup termcap info
  793.  */
  794. init_term()
  795.     {
  796.     char termbuf[1024];
  797.     char *capptr = cap+10;
  798.     char *term;
  799.  
  800. # ifdef MSDOS
  801.     term = getenv("TERM");
  802.     if (term == NULL)
  803.         term = "ibmpc-mono";
  804.     switch (tgetent(termbuf, term))
  805. # else
  806. # ifdef VMS
  807.     term = getenv("TERM");
  808.     if (term == NULL)
  809.         term = getenv("TERMINAL");
  810.     switch (tgetent(termbuf, term))
  811. # else
  812.     switch (tgetent(termbuf, term = getenv("TERM")))
  813. # endif
  814. # endif
  815.         {
  816.         case -1: 
  817.             write(2, "Cannot open termcap file.\n", 26); exit();
  818.         case 0: 
  819.             write(2, "Cannot find entry of ", 21);
  820.             write(2, term, strlen (term));
  821.             write(2, " in termcap\n", 12);
  822.             exit();
  823.         };
  824.  
  825.     CM = tgetstr("cm", &capptr);  /* Cursor motion */
  826.     CE = tgetstr("ce", &capptr);  /* Clear to eoln */
  827.     CL = tgetstr("cl", &capptr);  /* Clear screen */
  828.  
  829. /* OPTIONAL */
  830.     AL = tgetstr("al", &capptr);  /* Insert line */
  831.     DL = tgetstr("dl", &capptr);  /* Delete line */
  832.     SO = tgetstr("so", &capptr);  /* Begin standout mode */
  833.     SE = tgetstr("se", &capptr);  /* End standout mode */
  834.     CD = tgetstr("cd", &capptr);  /* Clear to end of display */
  835.     TI = tgetstr("ti", &capptr);  /* Terminal initialization */
  836.     TE = tgetstr("te", &capptr);  /* Terminal end */
  837.  
  838.     if (!CM)    /* can't find cursor motion entry */
  839.         {
  840.         write(2, "Sorry, for a ",13);       write(2, term, strlen(term));
  841.         write(2, ", I can't find the cursor motion entry in termcap\n",50);
  842.         exit();
  843.         }
  844.     if (!CE)    /* can't find clear to end of line entry */
  845.         {
  846.         write(2, "Sorry, for a ",13);       write(2, term, strlen(term));
  847.         write(2,", I can't find the clear to end of line entry in termcap\n",57);
  848.         exit();
  849.         }
  850.     if (!CL)    /* can't find clear entire screen entry */
  851.         {
  852.         write(2, "Sorry, for a ",13);       write(2, term, strlen(term));
  853.         write(2, ", I can't find the clear entire screen entry in termcap\n",56);
  854.         exit();
  855.         }
  856.     if ((outbuf=(char *)malloc(BUFBIG+16))==0) /* get memory for decoded output buffer*/
  857.         {
  858.         write(2,"Error malloc'ing memory for decoded output buffer\n",50);
  859.         died(-285); /* malloc() failure */
  860.         }
  861.     }
  862. #endif VT100
  863.  
  864. /*
  865.  * cl_line(x,y)  Clear the whole line indicated by 'y' and leave cursor at [x,y]
  866.  */
  867. cl_line(x,y)
  868.     int x,y;
  869.     {
  870. #ifdef VT100
  871.     cursor(x,y);        lprcat("\33[2K");
  872. #else VT100
  873.     cursor(1,y);        *lpnt++ = CL_LINE;      cursor(x,y);
  874. #endif VT100
  875.     }
  876.  
  877. /*
  878.  * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
  879.  */
  880. cl_up(x,y)
  881.     register int x,y;
  882.     {
  883. #ifdef VT100
  884.     cursor(x,y);  lprcat("\33[1J\33[2K");
  885. #else VT100
  886.     register int i;
  887.     cursor(1,1);
  888.     for (i=1; i<=y; i++)   { *lpnt++ = CL_LINE;  *lpnt++ = '\n'; }
  889.     cursor(x,y);
  890. #endif VT100
  891.     }
  892.  
  893. /*
  894.  * cl_dn(x,y)   Clear screen from [1,y] to end of display. Leave cursor at [x,y]
  895.  */
  896. cl_dn(x,y)
  897.     register int x,y;
  898.     {
  899. #ifdef VT100
  900.     cursor(x,y); lprcat("\33[J\33[2K");
  901. #else VT100
  902.     register int i;
  903.     cursor(1,y);
  904.     if (!CD)
  905.         {
  906.         *lpnt++ = CL_LINE;
  907.         for (i=y; i<=24; i++) { *lpnt++ = CL_LINE;  if (i!=24) *lpnt++ = '\n'; }
  908.         cursor(x,y);
  909.         }
  910.     else
  911.         *lpnt++ = CL_DOWN;
  912.     cursor(x,y);
  913. #endif VT100
  914.     }
  915.  
  916. /*
  917.  * standout(str)    Print the argument string in inverse video (standout mode).
  918.  */
  919. standout(str)
  920.     register char *str;
  921.     {
  922. #ifdef VT100
  923.     setbold();
  924.     while (*str)
  925.         *lpnt++ = *str++;
  926.     resetbold();
  927. #else VT100
  928.     *lpnt++ = ST_START;
  929.     while (*str)
  930.         *lpnt++ = *str++;
  931.     *lpnt++ = ST_END;
  932. #endif VT100
  933.     }
  934.  
  935. /*
  936.  * set_score_output()   Called when output should be literally printed.
  937.  */
  938. set_score_output()
  939.     {
  940.     enable_scroll = -1;
  941.     }
  942.  
  943. /*
  944.  *  lflush()                        Flush the output buffer
  945.  *
  946.  *  Returns nothing of value.
  947.  *  for termcap version: Flush output in output buffer according to output
  948.  *                       status as indicated by `enable_scroll'
  949.  */
  950. #ifndef VT100
  951. static int scrline=18; /* line # for wraparound instead of scrolling if no DL */
  952. lflush ()
  953.     {
  954.     register int lpoint;
  955.     register char *str;
  956.     static int curx = 0;
  957.     static int cury = 0;
  958.  
  959.     if ((lpoint = lpnt - lpbuf) > 0)
  960.         {
  961. #ifdef EXTRA
  962.         c[BYTESOUT] += lpoint;
  963. #endif
  964.         if (enable_scroll <= -1) {
  965.             flush_buf();
  966. # ifdef MSDOS
  967.             /* Catch write errors on save files
  968.              */
  969.                 if (write(lfd,lpbuf,lpoint) != lpoint) {
  970.                     if (save_mode)
  971.                         longjmp(save_jbuf, -1);
  972.                     else
  973.                         warn("Error writing output file\n");
  974.                 }
  975. # else
  976.                 if (write(lfd,lpbuf,lpoint) != lpoint)
  977.                 write(2,"error writing to output file\n",29);
  978. # endif
  979.             lpnt = lpbuf;   /* point back to beginning of buffer */
  980.             return;
  981.         }
  982.         for (str = lpbuf; str < lpnt; str++)
  983.             {
  984.             if (*str>=32)   { ttputch (*str); curx++; }
  985.             else switch (*str) {
  986.                 case CLEAR:     tputs (CL, 1, ttputch);     curx = cury = 0;
  987.                                 break;
  988.  
  989.                 case CL_LINE:   tputs (CE, 1, ttputch);
  990.                                 break;
  991.  
  992.                 case CL_DOWN:   tputs (CD, 1, ttputch);
  993.                                 break;
  994.  
  995.                 case ST_START:  tputs (SO, 1, ttputch);
  996.                                 break;
  997.  
  998.                 case ST_END:    tputs (SE, 1, ttputch);
  999.                                 break;
  1000.  
  1001.                 case CURSOR:    curx = *++str - 1;      cury = *++str - 1;
  1002.                                 tputs (tgoto (CM, curx, cury), 1, ttputch);
  1003.                                 break;
  1004.  
  1005.                 case '\n':      if ((cury == 23) && enable_scroll)
  1006.                                   {
  1007.                                   if (!DL || !AL) /* wraparound or scroll? */
  1008.                                     {
  1009.                                     if (++scrline > 23) scrline=19;
  1010.  
  1011.                                     if (++scrline > 23) scrline=19;
  1012.                                     tputs (tgoto (CM, 0, scrline), 1, ttputch);
  1013.                                     tputs (CE, 1, ttputch);
  1014.  
  1015.                                     if (--scrline < 19) scrline=23;
  1016.                                     tputs (tgoto (CM, 0, scrline), 1, ttputch);
  1017.                                     tputs (CE, 1, ttputch);
  1018.                                     }
  1019.                                   else
  1020.                                     {
  1021.                                     tputs (tgoto (CM, 0, 19), 1, ttputch);
  1022.                                     tputs (DL, 1, ttputch);
  1023.                                     tputs (tgoto (CM, 0, 23), 1, ttputch);
  1024.                                 /*  tputs (AL, 1, ttputch); */
  1025.                                     }
  1026.                                   }
  1027.                                 else
  1028.                                   {
  1029.                                   ttputch ('\n');       cury++;
  1030.                                   }
  1031.                                 curx = 0;
  1032.                                 break;
  1033.                 case T_INIT:
  1034.                     if (TI)
  1035.                         tputs(TI, 1, ttputch);
  1036.                     break;
  1037.                 case T_END:
  1038.                     if (TE)
  1039.                         tputs(TE, 1, ttputch);
  1040.                     break;
  1041.                 default:
  1042.                     ttputch (*str);
  1043.                     curx++;
  1044.                 }
  1045.             }
  1046.         }
  1047.     lpnt = lpbuf;
  1048.     flush_buf();    /* flush real output buffer now */
  1049.     }
  1050. #else VT100
  1051. /*
  1052.  *  lflush()                        flush the output buffer
  1053.  *
  1054.  *  Returns nothing of value.
  1055.  */
  1056. lflush()
  1057.     {
  1058.     register int lpoint;
  1059.     if ((lpoint = lpnt - lpbuf) > 0)
  1060.         {
  1061. #ifdef EXTRA
  1062.         c[BYTESOUT] += lpoint;
  1063. #endif
  1064.         if (write(lfd,lpbuf,lpoint) != lpoint)
  1065.             write(2,"error writing to output file\n",29);
  1066.         }
  1067.     lpnt = lpbuf;   /* point back to beginning of buffer */
  1068.     }
  1069. #endif VT100
  1070.  
  1071. #ifndef VT100
  1072. static int index=0;
  1073. /*
  1074.  * ttputch(ch)      Print one character in decoded output buffer.
  1075.  */
  1076. static int ttputch(c)
  1077. int c;
  1078.     {
  1079.     outbuf[index++] = c;
  1080.     if (index >= BUFBIG)  flush_buf();
  1081.     }
  1082.  
  1083. /*
  1084.  * flush_buf()          Flush buffer with decoded output.
  1085.  */
  1086. static flush_buf()
  1087.     {
  1088.     if (index) write(lfd, outbuf, index);
  1089.     index = 0;
  1090.     }
  1091.  
  1092. /*
  1093.  *  char *tmcapcnv(sd,ss)  Routine to convert VT100 escapes to termcap format
  1094.  *
  1095.  *  Processes only the \33[#m sequence (converts . files for termcap use 
  1096.  */
  1097. char *tmcapcnv(sd,ss)  
  1098.     register char *sd,*ss;
  1099.     {
  1100.     register int tmstate=0; /* 0=normal, 1=\33 2=[ 3=# */
  1101.     char tmdigit=0; /* the # in \33[#m */
  1102.     while (*ss)
  1103.         {
  1104.         switch(tmstate)
  1105.             {
  1106.             case 0: if (*ss=='\33')  { tmstate++; break; }
  1107.               ign:  *sd++ = *ss;
  1108.               ign2: tmstate = 0;
  1109.                     break;
  1110.             case 1: if (*ss!='[') goto ign;
  1111.                     tmstate++;
  1112.                     break;
  1113.             case 2: if (isdigit(*ss)) { tmdigit= *ss-'0'; tmstate++; break; }
  1114.                     if (*ss == 'm') { *sd++ = ST_END; goto ign2; }
  1115.                     goto ign;
  1116.             case 3: if (*ss == 'm')
  1117.                         {
  1118.                         if (tmdigit) *sd++ = ST_START;
  1119.                             else *sd++ = ST_END;
  1120.                         goto ign2;
  1121.                         }
  1122.             default: goto ign;
  1123.             };
  1124.         ss++;
  1125.         }
  1126.     *sd=0; /* NULL terminator */
  1127.     return(sd);
  1128.     }
  1129. #endif VT100
  1130.  
  1131. /*
  1132.  *  beep()      Routine to emit a beep if enabled (see no-beep in .larnopts)
  1133.  */
  1134. beep() {
  1135.     if (!nobeep) *lpnt++ = '\7';
  1136.     }
  1137.